/*
 * DownloadItem.java
 *
 * Copyright 2007, 2008 Tiberiumlabs
 *
 * This file is part of Tiberiumlabs Lailaps.
 *
 * Tiberiumlabs Lailaps is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Tiberiumlabs Lailaps is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.tiberiumlabs.lailaps.list;

import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.util.URIUtil;
import org.tiberiumlabs.lailaps.settings.ApplicationSettings;
import org.tiberiumlabs.lailaps.settings.Settings;

/**
 * @author <a href="mailto:paranoid.tiberiumlabs@gmail.com">Paranoid</a>
 */
public class DownloadItem {

    private static final int HASH_INC = "DownloadItem".hashCode();

    private static final ApplicationSettings APPLICATION_SETTINGS = Settings.getApplicationSettings();

    public static final String getFilenameFromUrl(String url) {

        // index of first symbol after last '/'
        int filenameStart = url.lastIndexOf('/') + 1;
        if (filenameStart > 0) {

            // index of '?' - then will go params, cant include them into result file name
            int paramsStart = url.indexOf('?', filenameStart);
            if (paramsStart < 0) {
                paramsStart = url.length();
            }

            /* now paramsStart cant be -1, it is or url.length() or index of '?'
             *
             * checking for two cases:
             * 1. url like "http://www.somesite.com/somedir/somefile/". it seems that we will
             * download index.html or something like that, but filename is empty. will try to
             * generate it from url.
             * 2. url like "http://www.somesite.com/somedir/somefile/?someparam=somevalue".
             * just like example 1 but with params, so need to generate filename from url and
             * ignore params.
             */
            if (filenameStart == paramsStart) {
                int protocolIndex = url.indexOf("://") + 3;
                return url.substring(protocolIndex, paramsStart-1).replace('/', '_');
            }

            // returning just filename, without path and without params
            String result = url.substring(filenameStart, paramsStart);
            // if we have ASCII combinations - lets decode it:
            if (result.indexOf('%') >= 0) {
                try {
                    // decoding string, that may contain ASCII combinations:
                    return URIUtil.decode(result);
                } catch (URIException ignore) {
                }
            }

            // if we still here - URIException caught. let's just return as is.
            return result;
        }

        return "";
    }

    // private fields with working data:
    private String url;
    private String outputFile = "";
    private String outputPath;
    private long fullSize = 0;
    private long completedSize = 0;
    private int status = StatusConstants.STOPPED;
    private boolean targetFileCreated = false;
    private int hash = 0;

    private long createdTime = System.currentTimeMillis();
    private long completedTime = -1;

    /**
     * Creates a new instance of DownloadItem
     */
    public DownloadItem(String url) {
        this.url = url;
        this.hash = url.hashCode() + HASH_INC;
        this.outputFile = getFilenameFromUrl(url);
    }
    public DownloadItem() {
    }

    public boolean equals(DownloadItem item) {
        if (hash == item.hash) {
            return url.equals(item.url);
        }
        return false;
    }

    @Override
    public boolean equals(Object obj) {
        try {
            return equals((DownloadItem)obj);
        } catch (Exception ignore) {
        }
        return false;
    }

    @Override
    public String toString() {
        return "DownloadItem[" + url + ']';
    }

    @Override
    public int hashCode() {
        if (hash == 0) {
            hash = url.hashCode() + HASH_INC;
        }
        return hash;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
        this.hash = url.hashCode() + HASH_INC;
    }

    public String getOutputFile() {
        return outputFile;
    }

    public void setOutputFile(String outputFile) {
        this.outputFile = outputFile;
    }

    public String getOutputPath() {
        return outputPath;
    }

    public String getSafeOutputPath() {
        if (outputPath != null && outputPath.length() > 0) {
            return outputPath;
        }
        return APPLICATION_SETTINGS.getOutputFolder();
    }

    public void setOutputPath(String outputPath) {
        if (outputPath.endsWith(ApplicationSettings.FILESEPARATOR)) {
            this.outputPath = outputPath;
            return;
        }
        this.outputPath = outputPath + ApplicationSettings.FILESEPARATOR;
    }

    public long getFullSize() {
        return fullSize;
    }

    public void setFullSize(long fullSize) {
        this.fullSize = fullSize;
    }

    public long getCompletedSize() {
        return completedSize;
    }

    public void setCompletedSize(long completedSize) {
        this.completedSize = completedSize;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public boolean isTargetFileCreated() {
        return targetFileCreated;
    }

    public void setTargetFileCreated(boolean fileCreated) {
        this.targetFileCreated = fileCreated;
    }

    private long speedTime = 0;
    private long speedCompleted = 0;
    private long prevSpeed = 0;
    public long getSpeed() {
        if (status == StatusConstants.COMPLETED) {
            return -1;
        }
        // if it is first get - return unknown value
        if (speedTime == 0) {
            speedTime = System.currentTimeMillis();
            speedCompleted = completedSize;
            return -1;
        }
        long currentTime = System.currentTimeMillis();
        double t = (currentTime - speedTime)/1000d; // calculate in seconds
        if (t < 0.1) {
            return prevSpeed;
        }
        long c = speedCompleted;

        // set values for next time
        speedCompleted = completedSize;
        speedTime = currentTime;

        // how many bytes downloaded:
        prevSpeed = (long)((completedSize - c)/t);
        return prevSpeed;
    }

    public long getCompletedTime() {
        return completedTime;
    }

    public void setCompletedTime(long completedTime) {
        this.completedTime = completedTime;
    }

    public long getCreatedTime() {
        return createdTime;
    }

    public void setCreatedTime(long createdTime) {
        this.createdTime = createdTime;
    }

    public HistoryItem toHistory() {
        return new HistoryItem(url, getSafeOutputPath() + outputFile, createdTime, completedTime, fullSize);
    }

}
